package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.user.*;
import com.atguigu.tingshu.user.config.WechatAccountConfig;
import com.atguigu.tingshu.user.factory.StrategyFactory;
import com.atguigu.tingshu.user.mapper.*;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.user.service.UserPaidTrackService;
import com.atguigu.tingshu.user.strategy.ItemTypeStrategy;
import com.atguigu.tingshu.user.strategy.impl.AlbumStrategy;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.joda.time.LocalDateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private WechatAccountConfig wechatAccountConfig;

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;

    @Autowired
    private UserPaidTrackService userPaidTrackService;

    @Autowired
    private UserPaidTrackMapper userPaidTrackMapper;

    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private VipServiceConfigMapper vipServiceConfigMapper;

    @Autowired
    private UserVipServiceMapper userVipServiceMapper;

/*    @Autowired
    private ItemTypeStrategy itemTypeStrategy;*/

    @Autowired
    private StrategyFactory strategyFactory;

    @Override
    public Map<String, Object> wxLogin(String code) {
        //调用微信登录的api
        WxMaJscode2SessionResult wxMaJscode2SessionResult = null;
        try {
            wxMaJscode2SessionResult = wxMaService.jsCode2SessionInfo(code);
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        //openid:每个人的微信都对应的一个唯一标识！
        String openid = wxMaJscode2SessionResult.getOpenid();
        //利用openid 实现登录或注册功能
        UserInfo userInfo = userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getWxOpenId, openid));
        //判断对象是否为空
        if (null == userInfo) {
            //说明要注册
            userInfo = new UserInfo();
            userInfo.setWxOpenId(openid);
            userInfo.setNickname("听友：" + System.currentTimeMillis());
            userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
            //保存数据到数据库
            userInfoMapper.insert(userInfo);
            //在此需要给当前的用户进行初始化充值；同步，异步；mq 发送消息
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_USER_REGISTER, userInfo.getId());
        }
        //说明登录：将数据存储到redis，与返回token
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        //组成缓存的key
        String userLoginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
        //存储数据
        redisTemplate.opsForValue().set(userLoginKey, userInfo, RedisConstant.USER_LOGIN_REFRESH_KEY_TIMEOUT, TimeUnit.SECONDS);
        //返回数据
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        return map;
    }

    @Override
    public UserInfoVo getUserInfo(Long userId) {
        //查询用户信息
        UserInfo userInfo = this.getById(userId);
        //创建一个目标对象
        UserInfoVo userInfoVo = new UserInfoVo();
        //属性拷贝
        BeanUtils.copyProperties(userInfo, userInfoVo);
        return userInfoVo;
    }

    @Override
    public void updateUser(Long userId, UserInfoVo userInfoVo) {
        UserInfo userInfo = new UserInfo();

        BeanUtils.copyProperties(userInfoVo, userInfo);
        userInfo.setId(userId);
        userInfoMapper.updateById(userInfo);

    }

    @Override
    public Map<Long, Integer> userIsPaidTrack(Long albumId, List<Long> trackIdList, Long userId) {
        //创建map集合
        Map<Long, Integer> map = trackIdList.stream().collect(Collectors.toMap(trackId -> trackId, trackId -> 0));
        //  判断用户是否购买过专辑：user_paid_album
        UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userId).eq(UserPaidAlbum::getAlbumId, albumId));
        if (null != userPaidAlbum) {
            // 当前用户购买了专辑
            return trackIdList.stream().collect(Collectors.toMap(trackId -> trackId, trackId -> 1));
        }
        //查询用户购买声音的集合列表
        List<UserPaidTrack> userPaidTrackList = userPaidTrackService.list(new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getUserId, userId).in(UserPaidTrack::getTrackId, trackIdList));
        //这个列表有可能为空
        if (!CollectionUtils.isEmpty(userPaidTrackList)) {
            //购买过声音
            for (UserPaidTrack userPaidTrack : userPaidTrackList) {
                map.put(userPaidTrack.getTrackId(), 1);
            }
        }
        //返回数据
        return map;
    }

    @Override
    public Boolean isPaidAlbum(Long albumId, Long userId) {
        // 判断用户是否购买过专辑：user_paid_album
        //先判断用户id再判断专辑id select * from user_paid_album where user_id = ? and album_id=?
        return null != userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userId).eq(UserPaidAlbum::getAlbumId, albumId));
    }

    @Override
    public List<Long> findUserPaidTrackList(Long albumId, Long userId) {
        //用户购买的声音列表在user_paid_track
        List<Long> userPaidTrackList = userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>()
                        .eq(UserPaidTrack::getAlbumId, albumId).eq(UserPaidTrack::getUserId, userId))
                .stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
        //用户购买的声音id列表
        return userPaidTrackList;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) {

        //返回策略对象
        ItemTypeStrategy itemTypeStrategy = strategyFactory.getStrategy(userPaidRecordVo.getItemType());
        itemTypeStrategy.savePaidRecord(userPaidRecordVo);

        //记录用户购买信息
       /* if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(userPaidRecordVo.getItemType())) {
            //购买专辑 user_paid_album
            UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userPaidRecordVo.getUserId()).eq(UserPaidAlbum::getAlbumId, userPaidRecordVo.getItemIdList().get(0)));
            if (null != userPaidAlbum) {
                return;
            }
            //创建对象保存数据
            userPaidAlbum = new UserPaidAlbum();
            //赋值
            userPaidAlbum.setOrderNo(userPaidRecordVo.getOrderNo());
            userPaidAlbum.setUserId(userPaidRecordVo.getUserId());
            userPaidAlbum.setAlbumId(userPaidRecordVo.getItemIdList().get(0));
            //保存数据
            userPaidAlbumMapper.insert(userPaidAlbum);
        } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(userPaidRecordVo.getItemType())) {
            //购买声音 user_paid_track 判断当前购买的声音id在表中是否存在! 利用关键字continue
            //用户要购买的声音列表
            List<Long> itemIdList = userPaidRecordVo.getItemIdList();
            //用户已购买的声音列表
            LambdaQueryWrapper<UserPaidTrack> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserPaidTrack::getUserId, userPaidRecordVo.getUserId())
                    .in(UserPaidTrack::getTrackId, itemIdList);
            //用户在已购买的列表中买了对应的声音
            List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(wrapper);
            //需要将这个集合变为set集合，通过trackId判断是否存在
            Set<Long> paidTrackIdSet = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toSet());

            //判空
            if (!CollectionUtils.isEmpty(userPaidTrackList)) {
                //有买过
                for (Long itemId : itemIdList) {
                    if (paidTrackIdSet.contains(itemId)) {
                        //continue:结束本次循环，进入下次循环
                        //return:结束方法调用，返回方法调用处
                        //break:结束当前循环
                        //需要将包含的声音添加到集合中，用来记录哪些声音购买过
                        //使用mq进行增加余额
                        continue;
                    }
                }

            }
            //没买过
            //根据声音id获取声音对象
            Result<TrackInfo> trackInfoResult = trackInfoFeignClient.getTrackInfo(userPaidRecordVo.getItemIdList().get(0));
            Assert.notNull(trackInfoResult, "查询声音信息失败");
            TrackInfo trackInfo = trackInfoResult.getData();
            Assert.notNull(trackInfo, "查询声音信息失败");
            for (Long trackId : itemIdList) {
                //创建对象保存数据
                UserPaidTrack userPaidTrack = new UserPaidTrack();
                userPaidTrack.setUserId(userPaidRecordVo.getUserId());
                userPaidTrack.setOrderNo(userPaidRecordVo.getOrderNo());
                userPaidTrack.setAlbumId(trackInfo.getAlbumId());
                userPaidTrack.setTrackId(trackId);
                //保存数据
                userPaidTrackMapper.insert(userPaidTrack);
            }

        } else {
            //购买vip user_vip_service - 可能要续期
            //获取购买时长；vip_service_config.id;
            Long vipServiceId = userPaidRecordVo.getItemIdList().get(0);
            // 获取vip服务信息
            VipServiceConfig vipServiceConfig = vipServiceConfigMapper.selectById(vipServiceId);
            Integer serviceMonth = vipServiceConfig.getServiceMonth();

            //保存数据
            UserVipService userVipService = new UserVipService();
            userVipService.setOrderNo(userPaidRecordVo.getOrderNo());
            userVipService.setUserId(userPaidRecordVo.getUserId());
            Date currentTime = new Date();
            userVipService.setStartTime(currentTime);
            //过期时间；第一种：第一次购买 第二种：续期
            //判断当前用户是否是vip并且未过期，续期
            UserInfo userInfo = userInfoMapper.selectById(userPaidRecordVo.getUserId());
            if (userInfo.getIsVip() == 1 && userInfo.getVipExpireTime().after(new Date())) {
*//*                //属于续期
                LocalDateTime localDateTime = new LocalDateTime(userInfo.getVipExpireTime());
                Date expireTime = localDateTime.plusMonths(serviceMonth).toDate();
                System.out.println("过期时间:" + expireTime);
                userVipService.setExpireTime(expireTime);*//*
                currentTime = userInfo.getVipExpireTime();
            }
*//*            else {
                //属于第一次购买
                userVipService.setExpireTime(new LocalDateTime(new Date()).plusMonths(serviceMonth).toDate());
            }*//*
            //创建对象
            LocalDateTime localDateTime = new LocalDateTime(currentTime);
            //获取过期时间
            Date expireTime = localDateTime.plusMonths(serviceMonth).toDate();
            //设置过期时间
            userVipService.setExpireTime(expireTime);
            //保存数据
            userVipServiceMapper.insert(userVipService);
            //修改用户vip标识
            userInfo.setIsVip(1);
            userInfo.setVipExpireTime(expireTime);
            this.updateById(userInfo);
        }*/
    }

    @Override
    public void updateVipExpireStatus() {
        //获取当前时间
        userInfoMapper.updateIsVip();
    }
}

